﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml;

namespace HuaXingSDK
{
    public abstract class HXSyncRequest<T> : HXRequest where T : HXSyncResponse
    {
        protected HXSyncRequest(string transCode) : base(transCode)
        {
        }

        public virtual T ToResponse()
        {
            return (T)Activator.CreateInstance(typeof(T), this.GetResponseXml());
        }
    }

    public abstract class HXAsynRequest : HXRequest
    {
        public HXTrans? TTrans { get; protected set; }

        protected HXAsynRequest(string transCode) : base(transCode)
        {

        }

        protected override void OnNode(XmlNode parentNode, string name, object value)
        {
            if (value is HXTrans)
            {
                value = (int) value;
            }
            base.OnNode(parentNode, name, value);
        }
    }

    public abstract class HXRequest : HXEncryptXml
    {
        public string ChannelCode { get; }
        public string ChannelFlow { get; }
        public int ChannelDate { get; }
        public int ChannelTime { get; }
        public string EncryptData { get; }
        public string TransCode { get; }
        public string MerchantId { get; private set; }
        public HXAppId AppId { get; set; }

        protected HXRequest(string transCode)
        {
            TransCode = transCode;
            ChannelCode = HXConfigs.渠道标识;
            MerchantId = HXConfigs.商户编号;
            AppId = HXAppId.PC;
            var date = DateTime.UtcNow.AddHours(8);
            ChannelDate = int.Parse(date.ToString("yyyyMMdd"));
            ChannelTime = int.Parse(date.ToString("HHmmss"));
            ChannelFlow = ChannelCode + ChannelDate + TransCode.Substring(TransCode.Length - 3);
            var id = HXConfigs.创建请求流水号(this);
            if (id.Length > 11)
                throw new ArgumentOutOfRangeException("创建流水号的返回值最大长度是11位。");
            ChannelFlow += id;
        }

        protected override string[] GetHeader()
        {
            return new[]
            {
                nameof(ChannelCode),
                nameof(ChannelFlow),
                nameof(ChannelDate),
                nameof(ChannelTime),
                nameof(EncryptData)
            };
        }

        protected override string[] GetBody()
        {
            var t = GetType();
            var header = GetHeader().ToList();
            var names = new List<string>();
            var ps = t.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            foreach (var p in ps)
            {
                if (header.Contains(p.Name))
                    continue;
                names.Add(p.Name);
            }
            return names.ToArray();
        }

        protected override string[] GetEncrypt()
        {
            var body = GetBody();
            return body.Where(i => !nameof(TransCode).Equals(i, StringComparison.OrdinalIgnoreCase))
                .ToArray();
        }

        protected override void OnNode(XmlNode parentNode, string name, object value)
        {
            if (value is HXAppId)
            {
                value = value.ToString();
            }
            else if (value is HXIDType)
            {
                value = "1010";
            }
            else if (value is HXDFFlag)
            {
                value = (int) value;
            }
            base.OnNode(parentNode, name, value);
        }
    }
}
